package com.jinmdz.fmis.api.admin.service;

import com.jinmdz.fmis.api.admin.model.administrativearea.AdministrativeAreaIdData;
import com.jinmdz.fmis.api.admin.model.administrativearea.AdministrativeAreaParentIdData;
import com.jinmdz.fmis.api.admin.model.administrativearea.AdministrativeAreaSaveData;
import com.jinmdz.fmis.api.admin.model.administrativearea.AdministrativeAreaTreeItem;
import com.jinmdz.fmis.api.api.model.common.IdData;
import com.jinmdz.fmis.api.api.model.common.IdVersionData;
import com.jinmdz.fmis.api.base.BaseService;
import com.jinmdz.fmis.api.model.config.dictionary.OperationLogCode;
import com.jinmdz.fmis.api.model.system.UserItem;
import com.jinmdz.fmis.api.wrapper.AreaWrapper;
import com.jinmdz.fmis.api.wrapper.OperationWrapper;
import com.jinmdz.fmis.common.ext.StringBuilderExt;
import com.jinmdz.fmis.common.util.BeanUtil;
import com.jinmdz.fmis.common.util.DataUtil;
import com.jinmdz.fmis.common.util.third.Pinyin4jUtil;
import com.jinmdz.fmis.core.base.BaseResult;
import com.jinmdz.fmis.core.exception.ActionException;
import com.jinmdz.fmis.core.model.SearchLoadData;
import com.jinmdz.fmis.core.util.JacksonUtil;
import com.jinmdz.fmis.dao.admin.dao.AdministrativeAreaDao;
import com.jinmdz.fmis.dao.admin.model.administrativearea.AdministrativeAreaEditItem;
import com.jinmdz.fmis.dao.admin.model.administrativearea.AdministrativeAreaListItem;
import com.jinmdz.fmis.mapper.entity.SystemAreaEntity;
import com.jinmdz.fmis.mapper.mapper.SystemAreaMapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;

/**
 * 行政区划Service
 *
 * @author LiCongLu
 * @date 2020-03-15 12:44
 */
@Service("administrativeAreaService")
public class AdministrativeAreaService extends BaseService {

    @Resource
    private AdministrativeAreaDao administrativeAreaDao;

    @Resource
    private SystemAreaMapper systemAreaMapper;

    @Resource
    private AreaWrapper areaWrapper;

    @Resource
    private OperationWrapper operationWrapper;

    @Resource
    private OperationLogCode operationLogCode;


    /**
     * 加载所有行政区划
     *
     * @param
     * @return
     * @author LiCongLu
     * @date 2020-03-15 12:47
     */
    public BaseResult<ArrayList<AdministrativeAreaTreeItem>> loadAdministrativeAreaTreeWithParentId(IdData data) {
        ArrayList<AdministrativeAreaListItem> listItems = administrativeAreaDao.listAdministrativeAreaListByParentId(data.getId());
        // 转化为树状机构集合
        ArrayList<AdministrativeAreaTreeItem> loadItems = new ArrayList<>();
        for (AdministrativeAreaListItem listItem : listItems) {
            AdministrativeAreaTreeItem loadItem = new AdministrativeAreaTreeItem();
            loadItem.setId(listItem.getId())
                    .setParentId(listItem.getParentId())
                    .setLabel(listItem.getAreaName());
            loadItems.add(loadItem);
        }
        return successList(loadItems);
    }

    /**
     * 加载所有行政区划
     *
     * @param data 请求数据
     * @return
     * @author LiCongLu
     * @date 2020-03-15 12:47
     */
    public BaseResult<SearchLoadData<AdministrativeAreaListItem>> loadAdministrativeAreaListWithParentId(AdministrativeAreaParentIdData data) {
        startPageData(data);
        ArrayList<AdministrativeAreaListItem> loadItems = administrativeAreaDao.listAdministrativeAreaListByParentId(data.getId());
        SearchLoadData<AdministrativeAreaListItem> loadData = getSearchLoadData(loadItems);
        return successData(loadData);
    }

    /**
     * 加载行政区划
     *
     * @param data 请求主键
     * @return
     * @author LiCongLu
     * @date 2020-03-15 12:47
     */
    public BaseResult<AdministrativeAreaSaveData> loadAdministrativeAreaWithId(AdministrativeAreaIdData data) {
        // 加载数据
        AdministrativeAreaSaveData loadData = new AdministrativeAreaSaveData();

        // 加载业务数据
        if (DataUtil.valid(data.getId())) {
            Integer loadId = data.getId();
            // 查询业务信息
            AdministrativeAreaEditItem loadItem = administrativeAreaDao.getAdministrativeAreaEditById(loadId);
            if (DataUtil.isNull(loadItem) || DataUtil.isNull(loadItem.getId(), loadItem.getVersion())) {
                return failure("主键错误，不存在此行政区划信息");
            }

            // 复制返回数据
            loadData = BeanUtil.copy2Bean(loadItem, loadData);
        }

        // 返回响应结果
        return successData(loadData);
    }

    /**
     * 保存行政区划信息
     *
     * @param userItem 当前帐号
     * @param data     保存数据
     * @return
     * @author LiCongLu
     * @date 2020-03-15 13:11
     */
    @Transactional(rollbackFor = Exception.class)
    public BaseResult saveAdministrativeArea(UserItem userItem, AdministrativeAreaSaveData data) throws ActionException {
        Integer id = data.getId();
        // 主键不为空
        if (DataUtil.valid(id)) {
            updateAdministrativeArea(userItem, data);
        } else {
            insertAdministrativeArea(userItem, data);
        }
        return success("保存成功");
    }

    /**
     * 插入行政区划信息
     *
     * @param userItem 当前帐号
     * @param data     请求数据
     * @return
     * @author LiCongLu
     * @date 2020-03-15 13:39
     */
    private Integer insertAdministrativeArea(UserItem userItem, AdministrativeAreaSaveData data) throws ActionException {
        // 创建实体
        SystemAreaEntity entity = getEntity(userItem, SystemAreaEntity.class);

        // 覆盖数据
        BeanUtil.copy2Bean(data, entity);

        // 对行政区划进行判断处理
        checkAdministrativeAreaValue(entity);

        // 新增行政区划
        systemAreaMapper.insertSystemArea(entity);
        // 判断保存行政区划结果
        if (DataUtil.invalid(entity.getId())) {
            throw exception("保存行政区划信息失败");
        }

        // 添加操作日志
        saveAdministrativeAreaLog(userItem, operationLogCode.getInsert(), data, null, entity);
        return entity.getId();
    }

    /**
     * 验证处理行政区划
     *
     * @param entity 行政区划
     * @return
     * @author LiCongLu
     * @date 2020-03-15 13:41
     */
    private void checkAdministrativeAreaValue(SystemAreaEntity entity) throws ActionException {

        // 判断父行政区划主键
        if (DataUtil.isNull(entity.getParentId())) {
            entity.setParentId(0).setParentCode("");
        }

        // 判断父行政区划名称
        if (DataUtil.invalid(entity.getParentCode())) {
            entity.setParentCode("");
        }

        // 判断禁用状态
        if (DataUtil.isNull(entity.getDisableState())) {
            entity.setDisableState(0);
        }

        // 判断排序值
        if (DataUtil.isNull(entity.getSort())) {
            entity.setSort(0);
        }

        // 判断是否省市区县
        if (DataUtil.isNull(entity.getAsProvinceCityCounty())) {
            entity.setAsProvinceCityCounty(0);
        }

        // 设置简拼
        entity.setAreaNameAbbr(Pinyin4jUtil.getPinyinAbbrToLowerCase(entity.getAreaName()));

        // 判断行政区划的重复性
        Integer administrativeAreaCodeId = administrativeAreaDao.getAreaIdByAreaCode(entity.getId(), entity.getAreaCode());
        if (DataUtil.valid(administrativeAreaCodeId)) {
            throw exception("存在重复的行政区划编码");
        }

        // 判断行政区划名称的重复性
        Integer administrativeAreaNameId = administrativeAreaDao.getAreaIdByAreaName(entity.getId(), entity.getAreaName(), entity.getParentId());
        if (DataUtil.valid(administrativeAreaNameId)) {
            throw exception("存在重复的行政区划名称");
        }

        // 纠正父编码
        if (DataUtil.valid(entity.getParentId())) {
            SystemAreaEntity parentEntity = systemAreaMapper.getSystemAreaById(entity.getParentId());
            if (DataUtil.isNull(parentEntity) || DataUtil.isNull(parentEntity.getId(), parentEntity.getVersion())) {
                throw exception("父行政区划主键错误，不存在此行政区划");
            }

            // 设置父行政区划代码
            entity.setParentCode(parentEntity.getAreaCode());
        }
    }

    /**
     * 添加修改行政区划记录
     *
     * @param userItem    当前帐号
     * @param logTypeCode 操作日志值
     * @param data        请求数据
     * @param oldValue    旧数据
     * @param entity      保存实体
     * @return
     * @author LiCongLu
     * @date 2020-03-15 13:56
     */
    private void saveAdministrativeAreaLog(UserItem userItem, Integer logTypeCode, AdministrativeAreaSaveData data, String oldValue, SystemAreaEntity entity) throws ActionException {
        // 操作日志字符串
        StringBuilderExt builder = new StringBuilderExt();
        builder.format("保存行政区划，父行政区划[{0}]，行政区划编码[{1}]，行政区划名称[{2}]，操作人员[{3}]"
                , data.getParentCode(), entity.getAreaCode(), entity.getAreaName(), userItem.getFullName());

        // 添加日志
        operationWrapper.operationLog(userItem, logTypeCode, builder.toString(), JacksonUtil.obj2Json(data), oldValue, JacksonUtil.obj2Json(entity));
    }

    /**
     * 更新行政区划
     *
     * @param userItem 当前帐号
     * @param data     请求数据
     * @return
     * @author LiCongLu
     * @date 2020-03-15 13:59
     */
    private void updateAdministrativeArea(UserItem userItem, AdministrativeAreaSaveData data) throws ActionException {
        // 验证主键和数据版本是否存在
        if (DataUtil.isNull(data.getId(), data.getVersion())) {
            throw exception("请求行政区划主键与行政区划版本号不能为空");
        }

        // 通过主键获取行政区划
        SystemAreaEntity entity = systemAreaMapper.getSystemAreaById(data.getId());
        if (DataUtil.isNull(entity) || DataUtil.isNull(entity.getId(), entity.getVersion())) {
            throw exception("行政区划主键错误，不存在此行政区划");
        }

        // 验证行政区划信息版本
        if (!DataUtil.equals(data.getVersion(), entity.getVersion())) {
            throw exception(versionError("行政区划"));
        }

        // 记录旧数据
        String oldValue = JacksonUtil.obj2Json(entity);

        // 覆盖数据
        BeanUtil.copy2Bean(data, entity);

        // 对行政区划进行判断处理
        checkAdministrativeAreaValue(entity);

        // 更新行政区划
        systemAreaMapper.updateSystemArea(entity);

        // 添加操作日志
        saveAdministrativeAreaLog(userItem, operationLogCode.getUpdate(), data, oldValue, entity);
    }

    /**
     * 删除指定id的行政区划记录
     *
     * @param userItem 当前帐号
     * @param data     主键和版本号
     * @return
     * @author LiCongLu
     * @date 2020-03-15 14:04
     */
    @Transactional(rollbackFor = Exception.class)
    public BaseResult deleteAdministrativeAreaWithId(UserItem userItem, ArrayList<IdVersionData> data) throws ActionException {
        // 判断删除主键集合是否存在
        if (DataUtil.invalid(data)) {
            throw exception("不存在要删除的行政区划");
        }

        // 验证主键是否重复
        if (data.size() != getRepeatIdSize(data)) {
            throw exception("行政区划主键存在重复");
        }

        // 记录行政区划集合
        ArrayList<AdministrativeAreaEditItem> loadItems = new ArrayList<>();

        // 进行遍历删除信息
        for (IdVersionData idData : data) {
            // 通过主键查询行政区划
            AdministrativeAreaEditItem loadItem = administrativeAreaDao.getAdministrativeAreaEditById(idData.getId());
            if (DataUtil.isNull(loadItem) || DataUtil.isNull(loadItem.getId(), loadItem.getVersion())) {
                throw exception("主键错误，不存在此行政区划");
            }

            // 验证行政区划版本
            if (!DataUtil.equals(loadItem.getVersion(), idData.getVersion())) {
                throw exception(versionError("行政区划"));
            }

            // 判断其子行政区划的个数
            Integer areaCount = administrativeAreaDao.getAreaCountByParentId(loadItem.getId());
            if (DataUtil.valid(areaCount)) {
                throw exception("存在子行政区划无法删除");
            }

            // 删除行政区划
            systemAreaMapper.deletedForSystemArea(loadItem.getId(), userItem.getId(), loadItem.getVersion());
            // 记录行政区划
            loadItems.add(loadItem);
        }

        // 添加操作日志信息
        deleteAdministrativeAreaLog(userItem, operationLogCode.getDelete(), data, loadItems);

        return success("删除成功");
    }

    /**
     * 添加修改记录
     *
     * @param userItem    当前帐号
     * @param logTypeCode 操作日志值
     * @param data        请求数据
     * @param loadItems   删除信息实体
     * @return
     * @author LiCongLu
     * @date 2020-03-15 14:12
     */
    private void deleteAdministrativeAreaLog(UserItem userItem, Integer logTypeCode, ArrayList<IdVersionData> data, ArrayList<AdministrativeAreaEditItem> loadItems) throws ActionException {
        // 操作日志字符串
        StringBuilderExt builder = new StringBuilderExt();
        builder.format("删除行政区划，操作人员[{1}]", userItem.getFullName());
        // 添加日志
        operationWrapper.operationLog(userItem, logTypeCode, builder.toString(), JacksonUtil.obj2Json(data), JacksonUtil.obj2Json(loadItems), null);
    }
}
